home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Meeting Pearls 4
/
Meeting Pearls Vol. IV (1996)(GTI - Schatztruhe)[!].iso
/
Pearls
/
dev
/
Oberon
/
OberonV4
/
system
/
KeplerPorts.Mod
(
.txt
)
< prev
next >
Wrap
Oberon Text
|
1995-06-12
|
16KB
|
369 lines
Syntax10.Scn.Fnt
MODULE KeplerPorts; (* J. Templ, 30.10.90/07.06.94 *)
(* Ports provide device independent drawing operations clipped on the port's borders.
All drawing and mouse coordinates are relative to the origin x0, y0, which is relative to the
top left corner of the port. Capital letter coordinates always denote screen coordinates.
IMPORT
Display, Display1, Fonts, Printer, TextPrinter;
CONST
Ceres = FALSE; (*conditional compilation*)
TYPE
Port* = POINTER TO PortDesc;
PortDesc* = RECORD (Display.FrameDesc)
x0*, y0*, scale*: INTEGER;
ext*: Port;
END ;
DisplayPort* = POINTER TO DisplayPortDesc;
DisplayPortDesc* = RECORD (PortDesc) END ;
PrinterPort* = POINTER TO PrinterPortDesc;
PrinterPortDesc* = RECORD (PortDesc) END ;
BalloonPort* = POINTER TO BalloonPortDesc;
BalloonPortDesc* = RECORD (PortDesc) END ;
(* ----------------- abstract port methods ------------------ *)
PROCEDURE (P: Port) FillRect* (x, y, w, h, col, pat, mode: INTEGER);
END FillRect;
PROCEDURE (P: Port) DrawString*(x, y: INTEGER; s: ARRAY OF CHAR; font: Fonts.Font; col, mode: INTEGER);
END DrawString;
(* ----------------- concrete port methods ------------------ *)
PROCEDURE (P: Port) CX*(x: INTEGER): INTEGER;
BEGIN RETURN P.X + (P.x0 + x) DIV P.scale
END CX;
PROCEDURE (P: Port) CY*(y: INTEGER): INTEGER;
BEGIN RETURN P.Y + P.H + (P.y0 + y) DIV P.scale
END CY;
PROCEDURE (P: Port) Cx*(X: INTEGER): INTEGER;
BEGIN RETURN (X - P.X) * P.scale - P.x0
END Cx;
PROCEDURE (P: Port) Cy*(Y: INTEGER): INTEGER;
BEGIN RETURN (Y - P.Y - P.H) * P.scale - P.y0
END Cy;
PROCEDURE (P: Port) DrawLine*(x1, y1, x2, y2, col, mode: INTEGER);
VAR x, y, dx, dy, d, inc, Xmin, Xmax, Ymin, Ymax: INTEGER;
BEGIN
x1 := P.CX(x1); y1 := P.CY(y1); x2 := P.CX(x2); y2 := P.CY(y2);
IF x1 < x2 THEN Xmin := x1; Xmax := x2 ELSE Xmin := x2; Xmax := x1 END;
IF y1 < y2 THEN Ymin := y1; Ymax := y2 ELSE Ymin := y2; Ymax := y1 END;
IF (y2-y1) < (x1-x2) THEN x := x1; x1 := x2; x2 := x; y := y1; y1 := y2; y2 := y END;
dx := 2*(x2-x1);
dy := 2*(y2-y1);
x := x1; y := y1; inc := 1;
IF dy > dx THEN d := dy DIV 2;
IF dx < 0 THEN inc := -1; dx := -dx END;
WHILE y <= y2 DO
P.FillRect(P.Cx(x), P.Cy(y), P.scale, P.scale, col, 5, mode);
INC(y); DEC(d, dx);
IF d < 0 THEN INC(d, dy); INC(x, inc) END
END
ELSE d := dx DIV 2;
IF dy < 0 THEN inc := -1; dy := -dy END;
WHILE x <= x2 DO
P.FillRect(P.Cx(x), P.Cy(y), P.scale, P.scale, col, 5, mode);
INC(x); DEC(d, dy);
IF d < 0 THEN INC(d, dx); INC(y, inc) END
END
END
END DrawLine;
PROCEDURE (P: Port) DrawRect*(x, y, w, h, col, mode: INTEGER);
BEGIN
IF P.scale = 1 THEN DEC(x); DEC(y);
P.FillRect(x, y, w+3, 3, col, 5, mode);
P.FillRect(x+w, y, 3, h+3, col, 5, mode);
P.FillRect(x, y+h, w+3, 3, col, 5, mode);
P.FillRect(x, y, 3, h+3, col, 5, mode)
ELSE
P.FillRect(x, y, w, P.scale, col, 5, mode);
P.FillRect(x+w-P.scale, y, P.scale, h, col, 5, mode);
P.FillRect(x, y+h-P.scale, w, P.scale, col, 5, mode);
P.FillRect(x, y, P.scale, h, col, 5, mode)
END
END DrawRect;
PROCEDURE HairEllipse (P: Port; X, Y, A, B, col, mode: INTEGER); (* due to B. Stamm *)
VAR x, y: INTEGER; d, dx, dy, x2, y2, a, a2, a8, b, b2, b8: LONGINT;
PROCEDURE Dot4(x1, x2, y1, y2, col, mode: INTEGER);
BEGIN
P.FillRect(x1, y1, P.scale, P.scale, col, 5, mode);
P.FillRect(x1, y2, P.scale, P.scale, col, 5, mode);
P.FillRect(x2, y1, P.scale, P.scale, col, 5, mode);
P.FillRect(x2, y2, P.scale, P.scale, col, 5, mode);
END Dot4;
BEGIN
IF A = B THEN (* circle *)
DEC(A);
x := A; y := 0; dx := 8*(x-1); dy := 8*y+4; d := 1 - 4*A;
WHILE x > y DO
Dot4(P.Cx(X-x-1), P.Cx(X+x), P.Cy(Y-y-1), P.Cy(Y+y), col, mode);
Dot4(P.Cx(X-y-1), P.Cx(X+y), P.Cy(Y-x-1), P.Cy(Y+x), col, mode);
INC(d, dy); INC(dy, 8); INC(y);
IF d >= 0 THEN DEC(d, dx); DEC(dx, 8); DEC(x) END
END;
IF x = y THEN Dot4(P.Cx(X-x-1), P.Cx(X+x), P.Cy(Y-y-1), P.Cy(Y+y), col, mode) END
ELSIF (A > 0) & (B > 0) THEN (* ellipse *)
DEC(A); DEC(B);
a := A; a2 := a*a; a8 := 8*a2; b := B; b2 := b*b; b8 := 8*b2;
x := A; y := 0; x2 := a*b2; y2 := 0; dx := b8*(a-1); dy := 4*a2; d := b2*(1- 4*a);
WHILE y2 < x2 DO
Dot4(P.Cx(X-x-1), P.Cx(X+x), P.Cy(Y-y-1), P.Cy(Y+y), col, mode);
INC(d, dy); INC(dy, a8); INC(y); INC(y2, a2);
IF d >= 0 THEN DEC(d, dx); DEC(dx, b8); DEC(x); DEC(x2, b2) END
END;
INC(d, 4*(x2+y2)-b2+a2);
WHILE x >= 0 DO
Dot4(P.Cx(X-x-1), P.Cx(X+x), P.Cy(Y-y-1), P.Cy(Y+y), col, mode);
DEC(d, dx); DEC(dx, b8); DEC(x);
IF d < 0 THEN INC(d, dy); INC(dy, a8); INC(y) END
END
END
END HairEllipse;
PROCEDURE (P: Port) DrawEllipse*(x, y, a, b, col, mode: INTEGER);
BEGIN HairEllipse(P, P.CX(x), P.CY(y), a DIV P.scale, b DIV P.scale, col, mode)
END DrawEllipse;
PROCEDURE (P: Port) DrawCircle*(x, y, r, col, mode: INTEGER);
BEGIN HairEllipse(P, P.CX(x), P.CY(y), r DIV P.scale, r DIV P.scale, col, mode)
END DrawCircle;
PROCEDURE Line2(P: Port; col, pat, mode, x1, x2, y1, y2: INTEGER);
BEGIN
x1 := P.Cx(x1); x2 := P.Cx(x2); y1 := P.Cy(y1); y2 := P.Cy(y2);
P.FillRect(x1, y1, x2-x1, P.scale, col, pat, mode);
P.FillRect(x1, y2, x2-x1, P.scale, col, pat, mode)
END Line2;
PROCEDURE (P: Port) FillCircle* (x, y, r, col, pat, mode: INTEGER);
VAR x1, y1, d, dx, dy: INTEGER;
BEGIN x := P.CX(x); y := P.CY(y); r := r DIV P.scale;
IF (P.X < x + r) & (x - r < P.X + P.W) & (P.Y < y + r) & (y - r < P.Y + P.H) THEN
x1 := r - 1; y1 := 0; dx := (x1-1)*8; dy := y1*8 + 4; d := 3 - r*4;
WHILE x1 > y1 DO
Line2(P, col, pat, mode, x-x1-1, x+x1, y-y1-1, y+y1);
IF d+dy >= 0 THEN Line2(P, col, pat, mode, x-y1-1, x+y1, y-x1-1, y+x1) END ;
INC(d, dy); INC(dy, 8); INC(y1);
IF d >= 0 THEN DEC(d, dx); DEC(dx, 8); DEC(x1) END
END;
IF x1 = y1 THEN Line2(P, col, pat, mode, x-x1-1, x+x1, y-y1-1, y+y1) END
END
END FillCircle;
PROCEDURE (P: Port) FillQuad* (x1, y1, x2, y2, x3, y3, x4, y4, col, pat, mode: INTEGER); (* by B. Stamm *)
TYPE LineParms = RECORD x,y,d,dx,dy,inx,iny,drawX,drawY: INTEGER END;
VAR x,y,RHS2,RHS3: INTEGER; left,right: LineParms;
PROCEDURE InitLineParms(x1,y1,x2,y2: INTEGER; VAR p: LineParms);
BEGIN
p.x := x1; p.dx := x2-x1; IF p.dx > 0 THEN p.inx := 1 ELSIF p.dx < 0 THEN p.inx := -1; p.dx := -p.dx ELSE p.inx := 0 END;
p.y := y1; p.dy := y2-y1; IF p.dy > 0 THEN p.iny := 1 ELSIF p.dy < 0 THEN p.iny := -1; p.dy := -p.dy ELSE p.iny := 0 END;
p.d := p.dy - p.dx; p.dx := 2*p.dx; p.dy := 2*p.dy;
END InitLineParms;
PROCEDURE LineStep(VAR p: LineParms);
(* H = (d(x,y) := (2*x - 2*x1 + 1)*dy - (2*y - 2*y1 + 1)*dx < 0) *)
BEGIN
WHILE p.d < 0 DO INC(p.x,p.inx); INC(p.d,p.dy) END;
p.drawX := p.x; p.drawY := p.iny DIV 2 + p.y;
DEC(p.d,p.dx); INC(p.y,p.iny);
END LineStep;
PROCEDURE Max4(a,b,c,d: LONGINT): LONGINT;
VAR m: LONGINT;
BEGIN m := a;
IF b > m THEN m := b END ;
IF c > m THEN m := c END ;
IF d > m THEN m := d END ;
RETURN m
END Max4;
PROCEDURE Min4(a,b,c,d: LONGINT): LONGINT;
VAR m: LONGINT;
BEGIN m := a;
IF b < m THEN m := b END ;
IF c < m THEN m := c END ;
IF d < m THEN m := d END ;
RETURN m
END Min4;
BEGIN (* Quadrangle *)
x1 := P.CX(x1); x2 := P.CX(x2); x3 := P.CX(x3); x4 := P.CX(x4);
y1 := P.CY(y1); y2 := P.CY(y2); y3 := P.CY(y3); y4 := P.CY(y4);
IF (Max4(x1, x2, x3, x4) >= P.X) & (Min4(x1, x2, x3, x4) <= P.X + P.W) &
(Max4(y1, y2, y3, y4) >= P.Y) & (Min4(y1, y2, y3, y4) <= P.Y + P.H) THEN
IF (y1>y2) OR (y1=y2) & (x1>x2) THEN x := x1; x1 := x2; x2 := x; y := y1; y1 := y2; y2 := y END;
IF (y2>y3) OR (y2=y3) & (x2>x3) THEN x := x2; x2 := x3; x3 := x; y := y2; y2 := y3; y3 := y END;
IF (y3>y4) OR (y3=y4) & (x3>x4) THEN x := x3; x3 := x4; x4 := x; y := y3; y3 := y4; y4 := y END;
IF (y1>y2) OR (y1=y2) & (x1>x2) THEN x := x1; x1 := x2; x2 := x; y := y1; y1 := y2; y2 := y END;
IF (y2>y3) OR (y2=y3) & (x2>x3) THEN x := x2; x2 := x3; x3 := x; y := y2; y2 := y3; y3 := y END;
IF (y1>y2) OR (y1=y2) & (x1>x2) THEN x := x1; x1 := x2; x2 := x; y := y1; y1 := y2; y2 := y END;
IF LONG(x2-x1)*LONG(y4-y1) > LONG(y2-y1)*LONG(x4-x1) THEN RHS2 := 2 ELSE RHS2 := 0 END;
IF LONG(x3-x1)*LONG(y4-y1) > LONG(y3-y1)*LONG(x4-x1) THEN RHS3 := 1 ELSE RHS3 := 0 END;
CASE RHS2 + RHS3 OF
| 0: InitLineParms(x1,y1,x2,y2,left); InitLineParms(x1,y1,x4,y4,right);
| 1: InitLineParms(x1,y1,x2,y2,left); InitLineParms(x1,y1,x3,y3,right);
| 2: InitLineParms(x1,y1,x3,y3,left); InitLineParms(x1,y1,x2,y2,right);
| 3: InitLineParms(x1,y1,x4,y4,left); InitLineParms(x1,y1,x2,y2,right);
END;
WHILE left.y # y2 DO
LineStep(left); LineStep(right);
P.FillRect(P.Cx(left.drawX),P.Cy(left.drawY),P.Cx(right.drawX)-P.Cx(left.drawX),P.scale,col,pat,mode)
END;
CASE RHS2 + RHS3 OF
| 0: InitLineParms(x2,y2,x3,y3,left);
| 1: InitLineParms(x2,y2,x4,y4,left);
| 2: InitLineParms(x2,y2,x4,y4,right);
| 3: InitLineParms(x2,y2,x3,y3,right);
END;
WHILE left.y # y3 DO
LineStep(left); LineStep(right);
P.FillRect(P.Cx(left.drawX),P.Cy(left.drawY),P.Cx(right.drawX)-P.Cx(left.drawX),P.scale,col,pat,mode)
END;
CASE RHS2 + RHS3 OF
| 0,2: InitLineParms(x3,y3,x4,y4,left);
| 1,3: InitLineParms(x3,y3,x4,y4,right);
END;
WHILE left.y # y4 DO
LineStep(left); LineStep(right);
P.FillRect(P.Cx(left.drawX),P.Cy(left.drawY),P.Cx(right.drawX)-P.Cx(left.drawX),P.scale,col,pat,mode)
END
END
END FillQuad;
(* ----------------- display drawing methods ------------------ *)
PROCEDURE (P: DisplayPort) DrawLine*(x1, y1, x2, y2, col, mode: INTEGER);
BEGIN Display1.Line(P, col, P.CX(x1), P.CY(y1), P.CX(x2), P.CY(y2), mode)
END DrawLine;
PROCEDURE (P: DisplayPort) DrawCircle*(x, y, r, col, mode: INTEGER);
BEGIN Display1.Circle(P, col, P.CX(x), P.CY(y), r DIV P.scale, mode)
END DrawCircle;
PROCEDURE (P: DisplayPort) DrawEllipse*(x, y, a, b, col, mode: INTEGER);
BEGIN Display1.Ellipse(P, col, P.CX(x), P.CY(y), a DIV P.scale, b DIV P.scale, mode);
END DrawEllipse;
PROCEDURE Intersect(F: Port; VAR X, Y, W, H: INTEGER): BOOLEAN;
VAR t: INTEGER;
BEGIN
t := X+W;
IF F.X > X THEN X := F.X END;
IF F.X+F.W < t THEN W := F.X+F.W-X ELSE W := t-X END;
IF W <= 0 THEN RETURN FALSE END;
t := Y+H;
IF F.Y > Y THEN Y := F.Y END;
IF F.Y+F.H < t THEN H := F.Y+F.H-Y ELSE H := t-Y END;
RETURN H > 0
END Intersect;
PROCEDURE (P: DisplayPort) DrawString*(x, y: INTEGER; s: ARRAY OF CHAR; font: Fonts.Font; col, mode: INTEGER);
VAR ch: CHAR; pat: LONGINT; X, i, dx, chx, chy, chw, chh, Y, oldX, oldY: INTEGER; fno: SHORTINT;
BEGIN fno := TextPrinter.FontNo(font);
X := P.CX(x); y := P.CY(y); ch := s[0]; i := 0;
WHILE ch # 0X DO
Display.GetChar(font.raster, ch, dx, chx, chy, chw, chh, pat);
IF Ceres THEN
X := X + chx; Y := y + chy;
IF (X >= P.X) & (X+chw <= P.X + P.W) & (Y >= P.Y) & (Y+chh <= P.Y + P.H) THEN
Display.CopyPattern(col, pat, X, Y, mode)
ELSE
oldX := X; oldY := Y;
IF Intersect(P, X, Y, chw, chh) THEN
Display.CopyBlock(X, Y, chw, chh, X - oldX, Y - oldY - 200, Display.replace);
Display.CopyPattern(col, pat, 0, -200, mode);
Display.CopyBlock(X - oldX, Y - oldY - 200, chw, chh, X, Y, Display.replace)
END
END
ELSE
Display.CopyPatternC(P, col, pat, X+chx, y+chy, mode)
END ;
INC(x, SHORT(TextPrinter.DX(fno, ch) DIV 3048));
X := P.CX(x + P.scale DIV 2); INC(i); ch := s[i]
END
END DrawString;
PROCEDURE (P: DisplayPort) FillRect* (x, y, w, h, col, pat, mode: INTEGER);
VAR xp, yp: INTEGER;
BEGIN
x := P.CX(x); y := P.CY(y); w := w DIV P.scale; h := h DIV P.scale;
xp := P.CX(0); yp := P.CY(0);
IF Ceres THEN
IF Intersect(P, x, y, w, h) THEN
Display.ReplPattern(col, Display1.ThisPattern(pat), x, y, w, h, mode)
END
ELSIF pat = 5 THEN (* solid fg *)
Display.ReplConstC(P, col, x, y, w, h, mode)
ELSE
Display.ReplPatternC(P, col, Display1.ThisPattern(pat), x, y, w, h, xp, yp, mode)
END
END FillRect;
(* ----------------- printer drawing methods ------------------ *)
PROCEDURE (P: PrinterPort) DrawLine* (x1, y1, x2, y2, col, mode: INTEGER);
BEGIN
x1 := P.CX(x1); y1 := P.CY(y1);
x2 := P.CX(x2); y2 := P.CY(y2);
Printer.Line(x1, y1, x2, y2)
END DrawLine;
PROCEDURE (P: PrinterPort) DrawCircle* (x, y, r, col, mode: INTEGER);
BEGIN Printer.Circle(P.CX(x), P.CY(y), r)
END DrawCircle;
PROCEDURE (P: PrinterPort) DrawEllipse* (x, y, a, b, col, mode: INTEGER);
BEGIN Printer.Ellipse(P.CX(x), P.CY(y), a, b)
END DrawEllipse;
PROCEDURE (P: PrinterPort) DrawString* (x, y: INTEGER; s: ARRAY OF CHAR; font: Fonts.Font; col, mode: INTEGER);
BEGIN
Printer.String(P.CX(x), P.CY(y), s, font.name)
END DrawString;
PROCEDURE (P: PrinterPort) FillRect* (x, y, w, h, col, pat, mode: INTEGER);
BEGIN
IF pat = 5 THEN Printer.ReplConst(P.CX(x), P.CY(y), w, h)
ELSE Printer.ReplPattern(P.CX(x), P.CY(y), w, h, pat)
END
END FillRect;
(* ----------------- methods for finding the bounding box------------------ *)
PROCEDURE MinMax(x, y: INTEGER; VAR min, max: INTEGER);
BEGIN IF x < y THEN min := x; max := y ELSE min := y; max := x END
END MinMax;
PROCEDURE BlowUp (P: Port; x, y, w, h: INTEGER);
BEGIN x := x + P.x0; y := y + P.y0;
IF x < P.X THEN P.W := P.W + P.X - x; P.X := x END ;
IF x + w > P.X + P.W THEN P.W := x + w - P.X END ;
IF y < P.Y THEN P.H := P.H + P.Y - y; P.Y := y END ;
IF y + h > P.Y + P.H THEN P.H := y + h - P.Y END
END BlowUp;
PROCEDURE (P: BalloonPort) DrawRect* (x, y, w, h, col, mode: INTEGER);
BEGIN P.DrawRect^(x, y, w, h, col, mode) (*BlowUp(P, x, y, w, h)*)
END DrawRect;
PROCEDURE (P: BalloonPort) DrawLine* (x1, y1, x2, y2, col, mode: INTEGER);
VAR minx, miny, maxx, maxy: INTEGER;
BEGIN
MinMax(x1, x2, minx, maxx);
MinMax(y1, y2, miny, maxy);
BlowUp(P, minx, miny, maxx - minx, maxy - miny)
END DrawLine;
PROCEDURE (P: BalloonPort) DrawCircle* (x, y, r, col, mode: INTEGER);
BEGIN BlowUp(P, x - r - 4 , y - r - 4, 2 * r + 4, 2 * r + 4)
END DrawCircle;
PROCEDURE (P: BalloonPort) DrawEllipse* (x, y, a, b, col, mode: INTEGER);
BEGIN BlowUp(P, x - a - 4, y - b - 4, 2 * a + 4, 2 * b + 4)
END DrawEllipse;
PROCEDURE StringWidth*(VAR s: ARRAY OF CHAR; f: Fonts.Font): INTEGER;
VAR fno: SHORTINT; ch: CHAR; dx, w, i, sdx, sx, sy, sw, sh: INTEGER; p: LONGINT;
BEGIN
fno := TextPrinter.FontNo(f);
w := 0; i := 0; ch := s[0];
WHILE ch # 0X DO
dx := SHORT(TextPrinter.DX(fno, ch) DIV 3048);
INC(w, dx); INC(i); ch := s[i]
END ;
IF i > 0 THEN Display.GetChar(f.raster, s[i-1], sdx, sx, sy, sw, sh, p);
sdx := sdx * 4;
IF sdx > dx THEN INC(w, sdx - dx) END
END ;
RETURN w
END StringWidth;
PROCEDURE (P: BalloonPort) DrawString* (x, y: INTEGER; s: ARRAY OF CHAR; font: Fonts.Font; col, mode: INTEGER);
BEGIN BlowUp(P, x, y+font.minY*4, StringWidth(s, font), font.height*4)
END DrawString;
PROCEDURE (P: BalloonPort) FillRect* (x, y, w, h, col, pat, mode: INTEGER);
BEGIN BlowUp(P, x, y, w, h)
END FillRect;
PROCEDURE (P: BalloonPort) FillCircle* (x, y, r, col, pat, mode: INTEGER);
BEGIN BlowUp(P, x - r - 4 , y - r - 4, 2 * r + 4, 2 * r + 4)
END FillCircle;
PROCEDURE (P: BalloonPort) FillQuad* (x1, y1, x2, y2, x3, y3, x4, y4, col, pat, mode: INTEGER);
BEGIN
MinMax(x1, x2, x1, x2); MinMax(x2, x3, x2, x3); MinMax(x3, x4, x3, x4);
MinMax(x2, x3, x2, x3); MinMax(x1, x2, x1, x2);
MinMax(y1, y2, y1, y2); MinMax(y2, y3, y2, y3); MinMax(y3, y4, y3, y4);
MinMax(y2, y3, y2, y3); MinMax(y1, y2, y1, y2);
BlowUp(P, x1, y1, x4 - x1, y4 - y1)
END FillQuad;
PROCEDURE InitBalloon*(P: BalloonPort);
BEGIN P.scale := 1;
P.X := 10000; P.Y := 10000;
P.W := -20000; P.H := -20000
END InitBalloon;
END KeplerPorts.